﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;

namespace DarazSdk
{
    /// <summary>
    /// Daraz接口请求客户端
    /// </summary>
    public class DarazClient 
    {

        /// <summary>
        /// 接口Key
        /// </summary>
        public string APIKey { get; set; } = "R9ei1xqNRXTzb-CRLTWhNrR4CkX_ULc3IZJP8wK4i5KA6DPCz2hj88Eh";


        /// <summary>
        /// UserID
        /// </summary>
        public string UserID { get; set; } = "yj495614@163.com";


        /// <summary>
        /// Timestamp
        /// </summary>
        public string Timestamp { get; set; } = DateTime.UtcNow.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss");

        /// <summary>
        /// Version
        /// </summary>
        public string Version { get; set; } = "1.0";


        /// <summary>
        /// Format
        /// </summary>
        public string Format { get; set; } = "json";


        /// <summary>
        /// 基础请求地址
        /// </summary>
        public string BaseUrl { get; set; } = "https://api.sellercenter.daraz.pk/";


        /// <summary>
        /// 请求前
        /// </summary>
        /// <param name="type">请求类型</param>
        /// <param name="url">请求地址</param>
        /// <param name="body">请求内容</param>
        public delegate void ExecutingEventHandler(string type, string url, string body);

        /// <summary>
        /// 请求后
        /// </summary>
        /// <param name="type">请求类型</param>
        /// <param name="url">请求地址</param>
        /// <param name="result">返回结果</param>
        public delegate void ExecuteEventHandler(string type, string url, string result);


        /// <summary>
        /// 请求前 触发
        /// </summary>
        public event ExecutingEventHandler OnExecuting;

        /// <summary>
        /// 请求后 触发
        /// </summary>
        public event ExecuteEventHandler OnExecute;


        protected HttpClient Client;

        /// <summary>
        /// Daraz接口请求客户端
        /// </summary>
        public DarazClient()
        {
            Client = new HttpClient();
        }


        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="action">请求方法</param>
        /// <param name="pairs"></param>
        /// <returns></returns>
        public async Task<string> GetAsStringAsync(string action, SortedDictionary<string, string>? pairs = null)
        {
            var url = $"{BaseUrl}?{CreateSignatureString(action, pairs)}";
            OnExecuting?.Invoke("GET", url, string.Empty);
            var res = await Client.GetAsync(url);
            var rs = await res.Content.ReadAsStringAsync();

            OnExecute?.Invoke("GET", url, rs);

            return rs;
        }

        /// <summary>
        /// Get请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        /// <param name="pairs"></param>
        /// <returns></returns>
        public async Task<DarazResult<T>> GetAsync<T>(string action, SortedDictionary<string, string>? pairs = null)
        {
            var rs = await GetAsStringAsync(action, pairs);
            var json = JObject.Parse(rs);
            var dr = new DarazResult<T>();
            if (json["ErrorResponse"] != null)
            {
                dr.ErrorResponse = json["ErrorResponse"]["Head"].ToString().JsonToObject<ErrorResponse>();
                dr.ResponseBody = rs;
            }
            else
            {
                dr.SuccessHeader = json["SuccessResponse"]["Head"].ToString().JsonToObject<SuccessHeader>();
                dr.Body = json["SuccessResponse"]["Body"].ToString().JsonToObject<T>();
            }
            return dr;
        }

        /// <summary>
        /// POST 请求
        /// </summary>
        /// <param name="action"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        public async Task<string> PostAsStringAsync(string action, string body = "")
        {
            var url = $"{BaseUrl}?{CreateSignatureString(action)}";
            var content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");
            OnExecuting?.Invoke("POST", url, body);
            var res = await Client.PostAsync(url, content);
            var rs = await res.Content.ReadAsStringAsync();
            OnExecute?.Invoke("POST", url, rs);

            return rs;
        }

        /// <summary>
        /// POST请求
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="body">请求内容</param>
        /// <returns></returns>
        public async Task<DarazResult<T1>> PostAsync<T, T1>(string action, T body) where T : class, new()
        {

            var bodyContent = body.ToRequestXmlBody();
            var rs = await PostAsStringAsync(action, bodyContent);
            var json = JObject.Parse(rs);
            var dr = new DarazResult<T1>();
            if (json["ErrorResponse"] != null)
            {
                dr.ErrorResponse = json["ErrorResponse"]["Head"].ToString().JsonToObject<ErrorResponse>();
                dr.ResponseBody = rs;
            }
            else
            {
                dr.SuccessHeader = json["SuccessResponse"]["Head"].ToString().JsonToObject<SuccessHeader>();
                dr.Body = json["SuccessResponse"]["Body"].ToString().JsonToObject<T1>();
            }
            return dr;
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <param name="fileInfos"></param>
        /// <returns></returns>
        public async Task<string> UploadAsStringAsync(string action, List<UploadFileInfo> fileInfos)
        {
            var pairs = new SortedDictionary<string, string>();
            var signature = CreateSignature(action);
            var content = new MultipartFormDataContent();
            foreach (var item in signature.dataArray)
            {
                content.Add(new StringContent(item.Value), item.Key);
            }
            //
            content.Add(new StringContent(signature.data), "Signature");

            fileInfos.ForEach(file =>
            {
                var fileKey = $"image_{DateTime.Now.ToString("fff")}";
                var fileName = $"{fileKey}{Path.GetExtension(file.FilePath)}";
                content.Add(new ByteArrayContent(File.ReadAllBytes(file.FilePath)), fileKey, fileName);
            });

            var rsp = await Client.PostAsync(BaseUrl, content);
            return await rsp.Content.ReadAsStringAsync();
        }

        /// <summary>
        /// 上传文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="action"></param>
        /// <param name="fileInfos"></param>
        /// <returns></returns>
        public async Task<DarazResult<T>> UploadAsync<T>(string action, List<UploadFileInfo> fileInfos)
        {
            var rs = await UploadAsStringAsync(action, fileInfos);
            var json = JObject.Parse(rs);
            var dr = new DarazResult<T>();
            if (json["ErrorResponse"] != null)
            {
                dr.ErrorResponse = json["ErrorResponse"]["Head"].ToString().JsonToObject<ErrorResponse>();
                dr.ResponseBody = rs;
            }
            else
            {
                dr.SuccessHeader = json["SuccessResponse"]["Head"].ToString().JsonToObject<SuccessHeader>();
                dr.Body = json["SuccessResponse"]["Body"].ToString().JsonToObject<T>();
            }
            return dr;
        }


        /// <summary>
        /// 创建签名排序支持 GET POST 挂在URL上面
        /// </summary>
        /// <param name="action">请求接口名</param>
        /// <param name="pairs">参数 GET可能需要</param>
        /// <returns></returns>
        string CreateSignatureString(string action, SortedDictionary<string, string>? pairs = null)
        {

            if (pairs == null)
            {
                pairs = new SortedDictionary<string, string>();
            }
            var p = new StringBuilder();
            pairs.TryAdd("UserID", UserID);
            pairs.TryAdd("Timestamp", Timestamp);
            pairs.TryAdd("Version", Version);
            pairs.TryAdd("Action", action);
            pairs.TryAdd("Format", Format);

            var signature = CreateSignature(action).data;

            foreach (var pair in pairs)
            {
                p.Append($"{RFC3986Encode.UrlEncode(pair.Key)}={RFC3986Encode.UrlEncode(pair.Value)}&");
            }
            p.Append($"Signature={signature}");
            return p.ToString();
        }




        /// <summary>
        /// 签名计算
        /// </summary>
        /// <param name="action"></param>
        /// <returns></returns>
        (string data, SortedDictionary<string, string> dataArray) CreateSignature(string action)
        {

            var dicSign = new SortedDictionary<string, string>();
            dicSign.TryAdd("UserID", UserID);
            dicSign.TryAdd("Timestamp", Timestamp);
            dicSign.TryAdd("Version", Version);
            dicSign.TryAdd("Action", action);
            dicSign.TryAdd("Format", Format);
            var s = new StringBuilder();
            foreach (var item in dicSign)
            {
                s.Append($"{RFC3986Encode.UrlEncode(item.Key)}={RFC3986Encode.UrlEncode(item.Value)}&");
            }
            var signStr = s.Remove(s.Length - 1, 1);
            return (SHA256Hash(signStr.ToString()), dicSign);
        }

        /// <summary>
        /// 加密算法
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        string SHA256Hash(string str)
        {
            var keys = Encoding.UTF8.GetBytes(APIKey);
            byte[] data = Encoding.ASCII.GetBytes(str);

            using HMACSHA256 hMACSHA256 = new HMACSHA256(keys);
            hMACSHA256.Initialize();
            var hashBytes = hMACSHA256.ComputeHash(data);
            return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
        }
    }
}

